package com.example.locat;

import android.util.Log;

import com.example.locat.abs.Location;
import com.example.locat.abs.Point;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;

/**
 * TrianBeacation = Triangulation + Beacon + Location
 */
public class TrianBeacation extends Location<BeacoNode> {

    @Override
    public Point getLocation() {
        /*
         * 获取离用户最近的3个beacon节点
         */

        BeacoNode[] closest3Nodes = getClosest3Nodes();
        if(closest3Nodes == null || closest3Nodes.length <3){
            Log.d("closest3Nodes length: ",closest3Nodes+"");
            return null;
        }
       /*  for (Double aDouble : getNodes().keySet()) {
            System.out.println(aDouble);
            List<BeacoNode> nodes1 = getNodes().get(aDouble);
            for(int j = 0;j<nodes1.size();j++){
                System.out.println(nodes1.get(j).toString());
            }

        }
        System.out.println("====================================");
        for(BeacoNode node: closest3Nodes){
            System.out.println(node);
        }*/
        double x=0,y=0;
        Point p1,p2,p3;
        double r1,r2,r3;

        p1 = closest3Nodes[0].getPoint();
        p2 = closest3Nodes[1].getPoint();
        p3 = closest3Nodes[2].getPoint();
        r1 = closest3Nodes[0].getDistence();
        r2 = closest3Nodes[1].getDistence();
        r3 = closest3Nodes[2].getDistence();
        //https://www.101computing.net/cell-phone-trilateration-algorithm/
        double A = 2 * p2.getX() - 2 * p1.getX();
        double B = 2 * p2.getY() - 2 * p1.getY();
        double C = Math.pow(r1,2) - Math.pow(r2,2) - Math.pow(p1.getX(),2)
                + Math.pow(p2.getX(),2) - Math.pow(p1.getY(),2) + Math.pow(p2.getY(),2);
        double D = 2 * p3.getX() - 2*p2.getX();
        double E = 2 * p3.getY() - 2*p2.getY();
        double F = Math.pow(r2,2) - Math.pow(r3,2) - Math.pow(p2.getX(),2)
                + Math.pow(p3.getX(),2) - Math.pow(p2.getY(),2) + Math.pow(p3.getY(),2);
        x = (C*E - F*B) / (E*A - B*D);
        y = (C*D - A*F) / (B*D - A*E);
    System.out.println("X: "+x + "Y: "+y);
        return new Point((int)Math.round(x),(int)Math.round(y));
    }

    /**
     * 获取node列表@list中最小的@count个node
     * @param list
     * @param count
     * @return
     */
    private BeacoNode[] getClosestNode(List<BeacoNode> list,int count){
        BeacoNode signalNode[] = new BeacoNode[count];
        for(int i=0;i<list.size();i++){
            for(int j=0;j<count;j++){
                if(signalNode[j] == null){
                    signalNode[j] = list.get(i);
                    break;
                }
                if(signalNode[j].getDistence() > list.get(i).getDistence()){
                    for(int k=count-1;k>j;k--){
                            signalNode[k] = signalNode[k-1];
                    }
                    signalNode[j] = list.get(i);
                    break;
                }
            }
        }
        return signalNode;
    }

    /**
     * 获取beacon列表里面最近的三个节点
     * 注意： 节点间会用major+minor进行隔离，
     * 因此不同的major+minor的节点间无法互通。
     * @return
     */
    private BeacoNode[] getClosest3Nodes() {
        BeacoNode beacoNodes[] = new BeacoNode[3];
        Set<Double> keys = getNodes().keySet();
        for(Double key : keys){
            List<BeacoNode> ns = getNodes().get(key);
            BeacoNode[] closestNode = getClosestNode(ns,3);
            if(beacoNodes[0] == null){
                beacoNodes = closestNode;
            }
            if(beacoNodes[0].getDistence() > closestNode[0].getDistence()){
                beacoNodes = closestNode;
            }
        }
        return beacoNodes;
    }

    private boolean isReady = false;

    /**
     * 将node存放到Map类型中，
     * 以major.minor的作为key,保证majro和minor相同的节点存放到同一个list中
     * 例如：major = 15,minor = 14，key = 15.14
     * @param node
     */
    @Override
    public TrianBeacation addNode(BeacoNode node){
        int major = node.getMajor();
        int minor = node.getMinor();
        double key = major + minor / Math.pow(10 ,(minor+"").length());
        List<BeacoNode> beacoNode = nodes.get(key);
        if(beacoNode == null || beacoNode.isEmpty()){
            beacoNode = new ArrayList<>();
        }
        beacoNode.add(node);
        nodes.put(key,beacoNode);

        return this;
    }

    public void removeAll(){
        nodes.clear();
    }


    @Override
    public TrianBeacation removeNode(BeacoNode node){
        int major = node.getMajor();
        int minor = node.getMinor();
        double key = major + minor / Math.pow(10 ,(minor+"").length());
        List<BeacoNode> beacoNode = nodes.get(key);
        if (beacoNode != null) {
            beacoNode.remove(node);
        }else{
            //TODO thow NodeNotExistException
        }
        return this;
    }
}
